﻿//==============================================================================
// Barrier 
//------------------------------------------------------------------------------
///**
//  @file       Barrier.h
//  @brief      Barrier
//  @author     Riki
//*/
//==============================================================================

#pragma once

#include "Atomic.h"
#include "Mutex.h"
#include "EventFlag.h"

namespace LNote
{
namespace Core
{
namespace Threading
{

//==============================================================================
// ■ Barrier
//------------------------------------------------------------------------------
///**
//  @brief      バリア同期を行うクラス
//*/
//==============================================================================
class Barrier
    : public Base::ReferenceObject
{
public:

	/// コンストラクタ (maxCount 個めのスレッドが wait() を呼ぶとすべて再開する。0 の場合は 1 になる。1の場合、wait を読んでも待機しない)
    Barrier( int maxCount );

	/// デストラクタ
    ~Barrier();

public:
	
	//----------------------------------------------------------------------
	///**
	//  @brief      他のスレッドを待つ
	//  @par
	//              コンストラクタで設定した数のスレッドがこの関数を呼び出すと、
	//              すべてのスレッドが実行されます。
	//*/
	//----------------------------------------------------------------------
    void wait();

	//----------------------------------------------------------------------
	///**
	//  @brief      同期の ON/OFF を設定する
	//  @par
	//              true を設定すると、wait() で待機中のすべてのスレッドが
	//              実行状態になり、以降、false が設定されるまで wait() は
	//              無効になります (待機しません)。
	//              デフォルトは false です。
	//*/
	//----------------------------------------------------------------------
    void setNotifyFlag( bool flag );
    
	//----------------------------------------------------------------------
	///**
	//  @brief      待機状態のスレッドをすべて実行状態にする
	//*/
	//----------------------------------------------------------------------
	//void notify();

private:

#if defined(LNOTE_WIN32)
    HANDLE  mFirstThreadSignal;
    HANDLE  mSignalWasDone;
    unsigned int    mMaxNum;
    Mutex           mExternalMutex;
	EventFlag		mAllLeaved;
    mutable unsigned int    mWaitThreadNum;     // スレッドが待機するごとに 1 ずつ減る
    CRITICAL_SECTION mCS;
    CRITICAL_SECTION mThreadNumCS;
#else
    pthread_mutex_t mMutex; 
    pthread_cond_t  mCond;
    unsigned int    mMaxNum;
    unsigned int    mWaitThreadNum;

#endif
    EventFlag       mNotifyFlag;
};

//==============================================================================
// ■ EventBarrier
//------------------------------------------------------------------------------
///**
//  @brief      
//  @note
//              1つのメインスレッドと複数のサブスレッドを同期させるためのクラス。      
//*/
//==============================================================================
class EventBarrier
    : public Base::ReferenceObject
{
public:

	/// コンストラクタ
    EventBarrier( int maxSubCount );

	/// デストラクタ
    ~EventBarrier();

public:
	
	//----------------------------------------------------------------------
	///**
	//  @brief      メインスレッド用の待機関数
	//  @par
	//              すべてのサブスレッドが待機状態になる/なっている場合、
	//              実行状態になります。
	//*/
	//----------------------------------------------------------------------
    void waitMain();

	//----------------------------------------------------------------------
	///**
	//  @brief      サブスレッド用の待機関数
	//*/
	//----------------------------------------------------------------------
    void waitSub();

	//----------------------------------------------------------------------
	///**
	//  @brief      待機状態すべてのサブスレッドを実行状態にする
	//  @note
	//              すべてのサブスレッドは待機中であること。
	//              また、この関数はメインスレッドから呼ぶこと。
	//*/
	//----------------------------------------------------------------------
    void notifyAllSub();

	//----------------------------------------------------------------------
	///**
	//  @brief      同期の ON/OFF を設定する
	//*/
	//----------------------------------------------------------------------
    void setNotifyFlag( bool flag );
    
private:
    int         mMaxWaitingSubNum;
    Atomic      mWaitingSubNum;
    Barrier     mBarrier;
    EventFlag   mMainNotifyFlag;
	Mutex		mMutex;
	EventFlag	mAllLeaved;
};

} // namespace Threading
} // namespace Core
} // namespace LNote

//==============================================================================
//
//==============================================================================